//
// Created by Vinson Cai on 2020/5/3.
//

#ifndef AIRPLAYLIBRARY_AIRPLAYRECEIVER_H
#define AIRPLAYLIBRARY_AIRPLAYRECEIVER_H

#if defined (_WIN32)
# define BZ_AIRPLAY_API __declspec(dllexport)
#include <stdint.h>
#else
# define BZ_AIRPLAY_API
#endif


#define BZ_AIRPLAY_VERSION              "1.2.9"

/// The maximum resolution string.
///  "480":  858 x  480,  480p Standard.
///  "720": 1280 x  720,  720p Standard.
///  "900": 1600 x  900.
/// "1080": 1920 x 1080, 1080p Standard.
/// "1440": 2560 x 1440,  720p Retina.
/// "2160": 3840 x 2160, 1080p Retina.
/// Empty : 1280 x  720,  720p Standard.
typedef enum _AirplayResolution{
    AIRPLAY_RESOLUTION_480 = 0X01,
    AIRPLAY_RESOLUTION_720 = 0X02,
    AIRPLAY_RESOLUTION_1080 = 0X03,
    AIRPLAY_RESOLUTION_1440 = 0X04,
    AIRPLAY_RESOLUTION_2160 = 0X05,
} AirplayResolution;


typedef enum _BZAirplayErrorCode {
    BZ_AIRPLAY_ERROR_CODE_OK        = 0X00,
    BZ_AIRPLAY_ERROR_GET_UID_FAILED = 0X03,
    BZ_AIRPLAY_ERROR_UID_INCOMPATIBLE = 0X04,
    BZ_AIRPLAY_ERROR_VALIDATE_FAILED = 0X05,
    BZ_AIRPLAY_ERROR_EXCEED_MAX_COUNT = 0X06,
    BZ_AIRPLAY_ERROR_CODE_IN_USED = 0X07,
    BZ_AIRPLAY_ERROR_CODE_INCOMPATIBLE = 0X08,
    BZ_AIRPLAY_ERROR_INVALID_PARAMETER = 0X09,
    BZ_AIRPLAY_ERROR_CODE_NEEDED = 0X0A,
    BZ_AIRPLAY_ERROR_CODE_NOT_FOUND = 0X0B,
    BZ_AIRPLAY_ERROR_SERVER_ERROR = 0X0C,
    BZ_AIRPLAY_ERROR_START_RAOP_FAILED = 0X10,
    BZ_AIRPLAY_ERROR_START_AIRPLAY_FAILED = 0X11,
    BZ_AIRPLAY_ERROR_START_MDNS_FAILED = 0X12,
    BZ_AIRPLAY_ERROR_REGISTER_RAOP_FAILD = 0x13,
    BZ_AIRPLAY_ERROR_REGISTER_AIRPLAY_FAILD = 0x14,


    BZ_AIRPLAY_ERROR_UNKNOWN = 0XFF,
} BZAirplayErrorCode;

typedef enum _AirplayOrientation {
    AIRPLAY_ORIENTATION_LANDSCAPE   = 0X01,
    AIRPLAY_ORIENTATION_VERTICAL    = 0X02,
} AirplayOrientation;

typedef enum _AirplayServiceMode {
    AIRPLAY_SERVICE_MIRROR = 0x00,//镜像模式
    AIRPLAY_SERVICE_PLAYER = 0x01,//推流模式
} AirplayServiceMode;

typedef enum _AirplayNetInterface {
    AIRPLAY_INTERFACE_WLAN = 0X01,
    AIRPLAY_INTERFACE_ETHERNET = 0X02,
} AirplayNetInterface;

typedef enum _AirplayAuthAllowStatus {
    AIRPLAY_AUTH_ALLOW_REJECT = 0x00,//请求授权拒绝
    AIRPLAY_AUTH_ALLOW_ACCEPT = 0x01,//请求授权接受
    AIRPLAY_AUTH_ALLOW_UNKNOWN = 0x02,//请求授权状态未知
}AirplayAuthAllowStatus;

typedef enum _AirplayDeviceModel {
    AIRPLAY_MODEL_IPHONE = 0x00,//iphone
    AIRPLAY_MODEL_IPAD = 0x01,//ipad
    AIRPLAY_MODEL_MACBOOK = 0x02,//MacBook
    AIRPLAY_MODEL_UNKNOWN = 0x03,//未知设备
}AirplayDeviceModel;

/**
 * 定义服务器的能力，如最大帧率，还有分辨率。
 */
typedef struct _AirplayReceiverAbility {
    char* ip;
    int maxVideoFps;
    AirplayResolution resolution;
    AirplayOrientation orientation;
} AirplayReceiverAbility;

typedef struct airplay_callbacks_s {
    void *cls;


    /**
     * 日志回调
     * @param msg
     */
    void (*airplay_log_callback)(const char* msg);

    /**
     * 当激活成功时回调，需要把返回的 @secret 保存好，下次再次启动时，把这个值传给 @activateSecret，这样就不需要再联网激活了。
     * @param secret 激活的密文，需要保存起来。
     */
    void (*airplay_activate_success)(const char* secret);

    /**
     * 激活失败时回调。
     * @param error
     * @param reason
     */
    void (*airplay_activate_failed)(BZAirplayErrorCode error, const char* reason);

    /**
     * 当有Airplay设备创建连接时回调
     * @param cls
     * @param 客户端的IP地址
     */
    void (*airplay_connection_create)(void *cls, const char* ip);
    /**
     * 当Airplay设备断开连接时回调
     * @param cls
     * @param 客户端的IP地址
     */
    void (*airplay_connection_teardown)(void *cls, const char* ip);

    /* Compulsory callback functions */
    /**
     * 开始启动推送，此时应该结束镜像的逻辑，开始播放推送过来的url链接
     * *注* 如果在启动推送之后还收到镜像数据，应该把镜像数据直接丢弃
     * @param cls
     * @param ip 客户端的IP地址
     * @param url 视频URL链接
     * @param fPosition 视频当前播放位置占视频总时长比例(范围0-1)
     * 优先使用fPosition计算视频当前播放位置，即（fPosition*总时长）。
     * 当fPosition为0时，使用dPosition作为视频当前播放位置。
     * !有些app推流时的视频初始位置值通过首次AirPlayPlayback_Seek告知。
     * @param dPosition 视频当前播放位置，以毫秒为单位
     */
    void(*AirPlayPlayback_Open) (void *cls, const char* ip, char *url, double fPosition, double dPosition);
    /**
      * @description 开始播放推送的视频流url和音频流url，仅做调试用，可忽略
      * @param cls
      * @param ip 客户端IP地址
      * @param videoUrl 视频流URL
      * @param audioUrl 音频流URL
      * @param fPosition 视频当前播放位置占视频总时长比例(范围0-1)
      * @param dPosition 视频当前播放位置，以毫秒为单位
      * @return
      * @author
      * @time 2022/8/9 21:14
     **/
    void(*AirPlayPlaybackDouble_Open) (void *cls, const char* ip, char *videoUrl,char *audioUrl, double fPosition, double dPosition);

    /**
     * Airplay设备推送【播放】指令，开始播放url链接
     * @param cls
     * @param ip 客户端的IP地址
     */
    void(*AirPlayPlayback_Play) (void *cls, const char* ip);

    /**
     * Airplay设备推送【暂停】指令，暂停播放url链接
     * @param cls
     * @param ip 客户端IP地址
     */
    void(*AirPlayPlayback_Pause)(void *cls, const char* ip);

    /**
     * Airplay设备关闭了播放url链接，可能视频播放结束或退出
     * @param cls
     * @param ip 客户端IP地址
     * @param ip 客户端IP地址
     */
    void(*AirPlayPlayback_Stop) (void *cls, const char* ip);

    /**
      * @description Airplay设备需要移除某个播放的url，播放音乐mv时可能会出现，暂时可忽略
      * @param cls 客户端的IP地址
      * @return
      * @author
      * @time 2022/8/30 9:45
     **/
    void (*AirplayPlayback_remove) (void *cls, const char* ip);

    /**
     * Airplay设备发送【快进】指令
     * @param cls
     * @param ip 客户端IP地址
     * @param fPosition 指定快进到某个位置，以毫秒为单位
     * 视频真正播放前首次回调值可能为初始播放位置，需要保存下来，等待视频开始播放时进行跳转
     */
    void(*AirPlayPlayback_Seek)(void *cls, const char* ip, long fPosition);

    /**
     * Airplay设备的推送模式更新音量，暂不支持
     * @param cls
     * @param ip
     * @param volume
     */
    void(*AirPlayPlayback_SetVolume)(void *cls, const char* ip, int volume);

    /**
     * Airplay设备的推送模式显示图片。
     * *注* 此接口未实现
     * @param cls
     * @param ip
     * @param data
     * @param size
     */
    void(*AirPlayPlayback_ShowPhoto)(void *cls, const char* ip, unsigned char *data, long long size);

    /**
     * Airplay设备推送模式时回调请求视频的总时长，以毫秒为单位
     * @param cls
     * @param ip 客户端IP地址
     * @return 视频总时长
     */
    long(*AirPlayPlayback_GetDuration)(void *cls,const char* ip);

    /**
     * Airplay设备推送模式时请求当前播放的位置，以毫秒为单位
     * @param cls
     * @param ip 客户端IP地址
     * @return 当前播放位置
     */
    long(*AirPlayPlayback_GetPosition)(void *cls, const char* ip);

    /**
     * Airplay设备推流模式时请求询问当前是否在播放
     * @param cls 
     * @param ip 客户端IP地址
     * @return 1：播放状态 0：非播放状态
     */
    int(*AirPlayPlayback_IsPlaying)(void *cls, const char* ip);

    /**
     * Airplay设备推流模式时询问当前是否暂停
     * @param cls 
     * @param ip 客户端IP地址
     * @return 1：暂停状态 0：非暂停状态
     */
    int(*AirPlayPlayback_IsPaused)(void *cls, const char* ip);

    /**
     * 镜像模式，开启音频流，初始化音频参数
     * @param cls
     * @param ip 客户端IP地址
     * @param bits 码率，请忽略
     * @param channels 通道数，默认是2，请忽略
     * @param samplerate 采样率。默认44100，请忽略
     * @param isaudio 是否音频，请忽略
     */
    void(*AirPlayAudio_Init)(void *cls, const char* ip, int bits, int channels, int samplerate, int isaudio);

    /**
     * 镜像模式的音频流回调
     * @param cls
     * @param ip 客户端IP地址
     * @param buffer 音频PCM数据流。
     * @param buflen 音频数据长度
     * @param timestamp 时间戳
     * @param seqnum 忽略
     */
    void(*AirPlayAudio_Process)(void *cls, const char* ip, const void *buffer, int buflen, uint64_t timestamp, uint32_t seqnum);

    /**
     * 镜像模式关闭音频流，释放内存
     * @param cls
     * @param ip 客户端IP地址
     */
    void(*AirPlayAudio_destroy)(void *cls, const char* ip);

    /**
     * 镜像模式更新音频的音量
     * @param cls
     * @param ip 客户端IP地址
     * @param volume 音量值（范围0-1）
     */
    void(*AirPlayAudio_SetVolume)(void *cls, const char* ip, float volume);

    /**
     * 忽略
     * @param cls
     * @param ip
     * @param buffer
     * @param buflen
     */
    void(*AirPlayAudio_SetMetadata) (void *cls, const char* ip, const void *buffer, int buflen);

    /**
     * 忽略
     * @param cls
     * @param ip
     * @param buffer
     * @param buflen
     */
    void(*AirPlayAudio_SetCovertArt)(void *cls, const char* ip, const void *buffer, int buflen);

    /**
     * 镜像模式时音频流清除缓存
     * @param cls
     * @param ip 客户端IP地址
     */
    void(*AirPlayAudio_Flush)(void *cls, const char* ip);

    /**
     * 回调更新Airplay设备名称,设备类型
     * @param cls
     * @param ip 客户端IP地址
     * @param name 设备名称
     */
    void(*AirplayUpdateDeviceInformation)(void* cls, const char* ip, const char* name,const AirplayDeviceModel model);

    /**
     * Airplay镜像模式启动
     * @param cls
     * @param ip 客户端IP地址
     */
    void(*AirPlayMirroring_start)(void *cls, const char* ip);

    /**
     * Airplay设备镜像视频流数据
     * @param cls
     * @param ip 设备地址
     * @param buffer 视频H264数据流
     * @param buflen 数据长度
     * @param timestamp 时间戳
     */
    void(*AirPlayMirroring_Process)(void *cls, const char* ip, const unsigned char *buffer, int buflen, uint64_t timestamp);

    /**
     * Airplay设备关闭镜像
     * @param cls
     * @param ip 客户端IP地址
     */
    void(*AirPlayMirroring_Stop)(void *cls, const char* ip);

    /**
     * Airplay设备发送心跳保活
     * @param cls
     * @param ip
     */
    void(*AirPlayMirroring_Live)(void *cls, const char* ip);

    /**
     * Airplay设备请求服务端的处理能力
     * @param cls
     * @param ability
     */
    void(*AirplayGetAbility)(void *cls, AirplayReceiverAbility* ability);

    /**
      * 通过BZAirplayReceiverSetAuthState开启设备连接密码验证时用到
      * @description Airplay设备输入密码正确连接成功时回调
      * @param ip 客户端IP地址
      * @param password 四位连接密码
      * @return
      * @author Wilson
      * @time 2022/7/1 11:05
     **/
    void(*AirplayAuthActivateSuccess)(void *cls,const char* ip,const char* password);

    /**
      * @description Airplay设备密码连接超时或失败时回调
      * @param ip 客户端IP地址
      * @param password 四位连接密码
      * @return
      * @author Wilson
      * @time 2022/7/1 11:08
     **/
    void(*AirplayAuthActivateFail)(void *cls,const char* ip,const char* password);

    /**
      * @description Airplay设备请求密码连接过程中回调
      * @param ip 客户端IP地址
      * @param password 四位连接密码
      * @return
      * @author Wilson
      * @time 2022/7/1 11:41
     **/
    void(*AirplayAuthActivating)(void *cls,const char* ip,const char* password);
    /**
      * 通过BZAirplayReceiverSetAuthManageNeed开启设备授权管理时用到
      * @description Airplay设备连接开始请求授权时回调
      * @param 客户端IP地址
      * @return
      * @author
      * @time 2022/11/1 10:36
     **/
    void (*AirplayAuthAllowConnectRequestStart)(void *cls,const char* ip);
    /**
      * 通过BZAirplayReceiverSetAuthManageNeed开启设备授权管理时用到
      * @description Airplay会回调请求是否允许客户端IP连接，会回调多次直到请求被拒绝、接受或授权超时
      * @param ip   客户端IP地址
      * @param status   请求用户授权允许状态指针
      * @return
      * @author
      * @time 2022/10/25 20:40
     **/
    void (*AirplayAuthAllowConnectRequesting)(void *cls,const char* ip,AirplayAuthAllowStatus* status);
    /**
      * 通过BZAirplayReceiverSetAuthManageNeed开启设备授权管理时用到
      * @description 客户端请求授权连接超时，主动断开连接
      * @param 客户端IP地址
      * @return
      * @author
      * @time 2022/10/28 19:56
     **/
    void (*AirplayAuthAllowConnectRequestTimeout)(void *cls,const char* ip);
} airplay_callbacks_t;

typedef struct airplay_parameter_s {


    //服务端的名称
    //e.g. "Airplay Demo".
    char name[64];

    //服务端Mac地址，
    //e.g. "aa:bb:cc:dd:ee:ff"
    char macAddress[32];

    //密码，可忽略
    char password[32];
    //缓存文件路径
    char fileDir[256];

    /// The maximum resolution string.
    ///  "480":  858 x  480,  480p Standard.
    ///  "720": 1280 x  720,  720p Standard.
    ///  "900": 1600 x  900.
    /// "1080": 1920 x 1080, 1080p Standard.
    /// "1440": 2560 x 1440,  720p Retina.
    /// "2160": 3840 x 2160, 1080p Retina.
    /// Empty : 1280 x  720,  720p Standard.
    AirplayResolution airplayResolution;
    bool discoverable;
    int targetFps;
    int supportUrl;

    /**
     * 激活时使用的网络接口，代表 @macAddress 是使用哪个网卡的地址
     */
    AirplayNetInterface activateInterface;
    /**
     * 激活码
     */
    char activateCode[20];
    /**
     * 激活密文。由服务器首次激活返回，需要应用层保存起来，后续直接提供Mac地址和这个密文，库就会校验这些信息，如果校验通过就不需要再次访问服务器。
     */
    char activateSecret[48];

    /**
     * 客户码信息，用于区分不同的客户。
     */
    char customerCode[48];

    /**
     * 平台信息。用于区分不同的平台。
     */
    char platformType[48];
    AirplayOrientation airplayOrientation;
    bool selfAnnounce;
    /**
      * 设置检测超时的时间，单位毫秒
      * 0表示由系统判断超时时间，大于0则使用自己设置的
     **/
    long checkTimeoutTime;
} airplay_parameter_t;



#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

#include <stdint.h>

/**
 * 开启Airplay服务
 * @param parameter  启动参数
 * @param cb 回调函数
 * @return
 */
int BZ_AIRPLAY_API BZAirplayReceiverStartServer(airplay_parameter_t* parameter, airplay_callbacks_t *cb);


/**
 * 关闭Airplay服务
 */
void BZ_AIRPLAY_API BZAirplayReceiverStopServer();

/**
 * 主动踢掉某个设备
 * @param 客户端IP地址
 */
void BZ_AIRPLAY_API BZAirplayReceiverKickOutClient(const char* ip);

/**
  * @description 打开或关闭Airplay设备连接密码
  * @param state 1：打开   0：关闭
  * @param password 自定义密码，密码长度小于64字节，不需用时可为NULL
  * @return
  * @author
  * @time 2022/7/1 18:54
 **/
void BZ_AIRPLAY_API BZAirplayReceiverSetAuthState(int state,const char* password);
/**
  * @description 打开或关闭是否需要对Airplay设备进行授权管理
  * @param need 1：需要     0：不需要
  * @return
  * @author
  * @time 2022/10/26 16:48
 **/
void BZ_AIRPLAY_API BZAirplayReceiverSetAuthManageNeed(int need);

/**
  * @description 更新Airplay设备连接密码
  * @param password 新的连接密码
  * @return
  * @author
  * @time 2022/7/5 11:15
 **/
void BZ_AIRPLAY_API BZAirplayReceiverUpdateDevicePassword(const char* password);
/**
  * @description 主动停止某个服务连接
  * @param ip 客户端IP地址
  * @param mode 镜像连接或推流连接
  * @return
  * @author
  * @time 2022/8/17 18:02
 **/
void BZ_AIRPLAY_API BZAirplayReceiverKickOutService(const char* ip,const AirplayServiceMode mode);

/**
  * @description 打开或关闭Airplay服务可发现
  * @param state 1:打开   0:关闭
  * @return
  * @author
  * @time 2022/12/12 11:25
 **/
void BZ_AIRPLAY_API BZAirplayReceiverSetDiscoverableState(int state);

/**
  * @description 更新airplay服务名称
  * @param
  * @return
  * @author
  * @time 2023/11/1 10:10
 **/
void BZ_AIRPLAY_API BZAirplayReceiverUpdateServerName(const char* name);

#ifdef __cplusplus
}
#endif  /* __cplusplus */

#endif //AIRPLAYLIBRARY_AIRPLAYRECEIVER_H
